//
// Created by 17259 on 2022/2/6.
//

#include "global.h"
#include "bright_ray.h"
#include "overworld.h"
#include "global.fieldmap.h"
#include "event_object_movement.h"
#include "fme.h"
#include "decompress.h"
#include "fieldmap.h"
#include "metatile_behavior.h"
#include "event_data.h"
#include "random.h"
#include "wild_encounter.h"
#include "event_scripts.h"
#include "string_util.h"
#include "data.h"
#include "dexnav.h"
#include "constants/trainer_types.h"
#include "constants/event_objects.h"
#include "constants/event_object_movement.h"

static bool8 IsTypeAggressive(u16 species)
{
    static const u8 AggressiveType[] = {TYPE_DARK, TYPE_FIGHTING, TYPE_FIRE,
                                        TYPE_ELECTRIC, TYPE_DRAGON,TYPE_GHOST};

    u16 i;
    for (i = 0; i < ARRAY_COUNT(AggressiveType); i++)
    {
        if (gBaseStats[species].type1 == AggressiveType[i] || gBaseStats[species].type2 == AggressiveType[i])
            return TRUE;
    }
    return FALSE;
}

void RemoveBrightRayObjectEvent(void)
{
    u16 i;
    const struct MapHeader *header;

    for (i = 0; i < OBJECT_EVENTS_COUNT; i++)
    {
        if (gObjectEvents[i].mapNum != gSaveBlock1Ptr->location.mapNum
            || gObjectEvents[i].mapGroup != gSaveBlock1Ptr->location.mapGroup)
        {
            if (!gObjectEvents[i].active || gObjectEvents[i].isPlayer
                || i == POF_GetFollowerObjectId())
                continue;

            header = Overworld_GetMapHeaderByGroupAndId(gObjectEvents[i].mapGroup, gObjectEvents[i].mapNum);
            if (gObjectEvents[i].localId > header->events->objectEventCount) //如果localId超过总数 说明是动态生成的明雷宝可梦
                RemoveObjectEvent(&gObjectEvents[i]);
        }
    }
}

static u16 LoadMapTiles(void)
{
    u16 i;
    const struct MapHeader* header = &gMapHeader;
    u8* flag = gDecompressionBuffer;
    u32 width = header->mapLayout->width;
    u32 left = 0;
    u32 right = header->mapLayout->width;
    u32 top = 0;
    u32 bottom = header->mapLayout->height;
    u32 encounterCount = 0;
    u32 x;

    CpuFill32(0, flag, width * header->mapLayout->height);
    for (i = 0; i < header->events->objectEventCount; i++)
    {
        struct ObjectEventTemplate* event = &header->events->objectEvents[i];
        flag[event->x + event->y * width] = ALREADY_HAS_OBJECT;
    }

    for( ; top < bottom; top++)
    {
        for (x = left; x < right; x++)
        {
            u32 pos = x + top * width;
            u8 metatileBehavior =
                    GetBehaviorByMetatileId(header->mapLayout->map[pos] & METATILE_ID_MASK) & 0xff;
            if (MetatileBehavior_IsEncounterTile(metatileBehavior) && flag[pos] != ALREADY_HAS_OBJECT)
            {
                flag[pos] = metatileBehavior;
                encounterCount++;
            }
        }
    }
    return encounterCount;
}

#define MIN(x, y) (((x) < (y)) ? (x) : (y))

static u8 GetBrightRayMonCount(u16 encounterCount)
{
    u8 maxCount = MIN(encounterCount / 20, BRIGHT_RAY_EVENT_TEMPLATES_COUNT_NORMAL);

    if (VarGet(VAR_REPEL_STEP_COUNT))
        maxCount = maxCount * 2 / 3;
    else if (VarGet(VAR_LURE_STEP_COUNT))
        maxCount = maxCount * 3 / 2;

    if (maxCount == 0)
        maxCount = 1;
    else if (maxCount + gMapHeader.events->objectEventCount > OBJECT_EVENT_TEMPLATES_COUNT)
        maxCount = OBJECT_EVENT_TEMPLATES_COUNT - gMapHeader.events->objectEventCount;

    return maxCount;
}

void TryGenerateBrightRayMons(void)
{
    u16 i = 0;
    const struct MapHeader* header = &gMapHeader;
    u8* flag = gDecompressionBuffer;
    u16 encounterCount = LoadMapTiles();
    u8 maxCount = GetBrightRayMonCount(encounterCount);

    gSaveBlock1Ptr->brightRayCount = maxCount;

    while (i < maxCount)
    {
        u32 postion = Random3(header->mapLayout->width * header->mapLayout->height);

        if (MetatileBehavior_IsEncounterTile(flag[postion]))
        {
            bool8 isWater;
            u16 species = GetLocalWildMon(&isWater);

            if (CanMonFollow(species)
                && !(isWater ^ MetatileBehavior_IsSurfableWaterOrUnderwater(flag[postion])))
            {
                struct ObjectEventTemplate result = {0};

                result.localId = header->events->objectEventCount + i + 1;
                result.x = postion % header->mapLayout->width;
                result.y = postion / header->mapLayout->width;
                if (Random() & 1)
                {
                    result.movementType = MOVEMENT_TYPE_WANDER_AROUND;
                    result.movementRangeX = Random3(2) + 1;
                    result.movementRangeY = Random3(2) + 1;
                }
                else
                {
                    result.movementType = MOVEMENT_TYPE_LOOK_AROUND;
                }
                result.flagId = FLAG_BRIGHT_RAY_START + i;
                result.script = EventScript_BrightRayBattle;
                result.graphicsId = NUM_REGULAR_OBJ_EVENT_GFX + species - 1;
                if (IsTypeAggressive(species) && VarGet(VAR_REPEL_STEP_COUNT) == 0)
                {
                    result.trainerType = TRAINER_TYPE_BRIGHT_RAY;
                    result.trainerRange_berryTreeId = 2;
                }
                gSaveBlock1Ptr->objectEventTemplates[header->events->objectEventCount + i] = result;
                flag[postion] = ALREADY_HAS_OBJECT;
                i++;
            }
        }
    }
}

void BufferBrightRayMon(void)
{
    gSpecialVar_0x8004 =
            GetObjectEventTemplateByLocalIdAndMap(gSpecialVar_LastTalked,
                                                  gSaveBlock1Ptr->location.mapNum,
                                                  gSaveBlock1Ptr->location.mapGroup)
                                                  ->graphicsId - NUM_REGULAR_OBJ_EVENT_GFX + 1;
    StringCopy(gStringVar1, gSpeciesNames[gSpecialVar_0x8004]);
}

void CreateBrightRayMon(void)
{
    u16 i;
    u16 headerId = GetCurrentMapWildMonHeaderId();
    const struct WildPokemonInfo *landMonsInfo = gWildMonHeaders[headerId].landMonsInfo;
    const struct WildPokemonInfo *waterMonsInfo = gWildMonHeaders[headerId].waterMonsInfo;

    if (landMonsInfo)
    {
        for (i = 0; i < 12; i++) //陆地上12种宝可梦
        {
            if (landMonsInfo->wildPokemon[i].species == gSpecialVar_0x8004)
            {
                u8 level = ChooseWildMonLevel(&landMonsInfo->wildPokemon[i]);
                CreateWildMon(landMonsInfo->wildPokemon[i].species, level);
                return;
            }
        }
    }

    if (waterMonsInfo)
    {
        for (i = 0; i < 5; i++) //水里5种宝可梦
        {
            if (waterMonsInfo->wildPokemon[i].species == gSpecialVar_0x8004)
            {
                u8 level = ChooseWildMonLevel(&waterMonsInfo->wildPokemon[i]);
                CreateWildMon(waterMonsInfo->wildPokemon[i].species, level);
                return;
            }
        }
    }
}
